home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1996 #15 / Monster Media Number 15 (Monster Media)(July 1996).ISO / bbs_util / bsrc_260.zip / SRC.ZIP / JANUS.C < prev    next >
C/C++ Source or Header  |  1996-03-23  |  70KB  |  2,203 lines

  1. /*--------------------------------------------------------------------------*/
  2. /*                                                                          */
  3. /*                                                                          */
  4. /*      ------------         Bit-Bucket Software, Co.                       */
  5. /*      \ 10001101 /         Writers and Distributors of                    */
  6. /*       \ 011110 /          Freely Available<tm> Software.                 */
  7. /*        \ 1011 /                                                          */
  8. /*         ------                                                           */
  9. /*                                                                          */
  10. /*              (C) Copyright 1987-96, Bit Bucket Software Co.              */
  11. /*                                                                          */
  12. /*                 This module was written by Rick Huebner                  */
  13. /*                 BinkleyTerm Janus revision 0.31, 11-2-89                 */
  14. /*                 Full-duplex WaZOO file transfer protocol                 */
  15. /*                                                                          */
  16. /*                                                                          */
  17. /*    For complete  details  of the licensing restrictions, please refer    */
  18. /*    to the License  agreement,  which  is published in its entirety in    */
  19. /*    the MAKEFILE and BT.C, and also contained in the file LICENSE.260.    */
  20. /*                                                                          */
  21. /*    USE  OF THIS FILE IS SUBJECT TO THE  RESTRICTIONS CONTAINED IN THE    */
  22. /*    BINKLEYTERM  LICENSING  AGREEMENT.  IF YOU DO NOT FIND THE TEXT OF    */
  23. /*    THIS  AGREEMENT IN ANY OF THE  AFOREMENTIONED FILES,  OR IF YOU DO    */
  24. /*    NOT HAVE THESE FILES,  YOU  SHOULD  IMMEDIATELY CONTACT BIT BUCKET    */
  25. /*    SOFTWARE CO.  AT ONE OF THE  ADDRESSES  LISTED BELOW.  IN NO EVENT    */
  26. /*    SHOULD YOU  PROCEED TO USE THIS FILE  WITHOUT HAVING  ACCEPTED THE    */
  27. /*    TERMS  OF  THE  BINKLEYTERM  LICENSING  AGREEMENT,  OR  SUCH OTHER    */
  28. /*    AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO.      */
  29. /*                                                                          */
  30. /*                                                                          */
  31. /* You can contact Bit Bucket Software Co. at any one of the following      */
  32. /* addresses:                                                               */
  33. /*                                                                          */
  34. /* Bit Bucket Software Co.        FidoNet  1:104/501, 1:343/491             */
  35. /* P.O. Box 460398                AlterNet 7:42/1491                        */
  36. /* Aurora, CO 80046               BBS-Net  86:2030/1                        */
  37. /*                                Internet f491.n343.z1.fidonet.org         */
  38. /*                                                                          */
  39. /* Please feel free to contact us at any time to share your comments about  */
  40. /* our software and/or licensing policies.                                  */
  41. /*                                                                          */
  42. /*--------------------------------------------------------------------------*/
  43.  
  44. /* Include this file before any other includes or defines! */
  45.  
  46. #include "includes.h"
  47.  
  48. #include "janus.h"
  49.  
  50. /* Private routines */
  51.  
  52. static void LOCALFUNC getfname (word);
  53. static void LOCALFUNC sendpkt (byte *, int, int);
  54. static void LOCALFUNC sendpkt32 (byte *, int, int);
  55. static void LOCALFUNC txbyte (byte);
  56. static long LOCALFUNC procfname (void);
  57. static byte LOCALFUNC rcvpkt (void);
  58. static void LOCALFUNC rxclose (word);
  59. static void LOCALFUNC endbatch (void);
  60. static void LOCALFUNC update_y (void);
  61. static void LOCALFUNC long_set_timer (long *, unsigned int);
  62. static int LOCALFUNC long_time_gone (long *);
  63. static int LOCALFUNC rcvrawbyte (void);
  64. static int LOCALFUNC rxbyte (void);
  65. static int LOCALFUNC get_filereq (byte);
  66. static int record_reqfile (char *);    /* ** NOT ** LOCALFUNC!!! */
  67. static int timeof_reqfile (long);    /* ** NOT ** LOCALFUNC!!! */
  68. static byte LOCALFUNC get_reqname (byte);
  69. static void LOCALFUNC mark_done (char *);
  70.  
  71. /* Common with HYDRA.C */
  72.  
  73. void j_message (unsigned int, char *,...);
  74. void j_status (char *,...);
  75. void j_msgend (short);
  76. int j_error (char *, char *);
  77. void xfer_summary (char *, char *, long *, short);
  78. void update_status (long *, long *, long, int *, short);
  79. long through (long *, long *);
  80.  
  81.  
  82. /* Private data. I know, proper software design says you shouldn't make data */
  83. /* global unless you really need to.  In this case speed and code size make  */
  84. /* it more important to avoid constantly pushing & popping arguments.        */
  85.  
  86. static char *GenericError = "!%s";
  87. static char *ReqTmpTempl = "JANUSREQ.%02x";
  88. static char ReqTmp[16];
  89. static char *Rxbuf;                /* Address of packet reception buffer              */
  90. static char *Txfname;            /* Full path of file we're sending                 */
  91. static char *Rxfname;            /* Full path of file we're receiving               */
  92. static byte *Rxbufptr;            /* Current position within packet reception buffer */
  93. static byte *Rxbufmax;            /* Upper bound of packet reception buffer          */
  94. static byte Do_after;            /* What to do with file being sent when we're done */
  95. static byte WaitFlag;            /* Tells rcvrawbyte() whether or not to wait       */
  96. static byte SharedCap;            /* Capability bits both sides have in common       */
  97. static int Txfile;                /* File handle of file we're sending               */
  98. static int Rxfile;                /* File handle of file we're receiving             */
  99. static int ReqRecorded;            /* Number of files obtained by this request        */
  100. static word TimeoutSecs;        /* How long to wait for various things             */
  101. static int Rxblklen;            /* Length of data in last data block packet recvd  */
  102. static int Next_y;                /* Number of next available line on screen         */
  103. static short Tx_y;                /* Line number of file transmission status display */
  104. static short Rx_y;                /* Line number of file reception status display    */
  105. static long Txlen;                /* Total length of file we're sending              */
  106. static long Rxlen;                /* Total length of file we're receiving            */
  107. static long Rxfiletime;            /* Timestamp of file we're receiving               */
  108. static long Diskavail;            /* Bytes available in upload directory             */
  109. static long Txsttime;            /* Time at which we started sending current file   */
  110. static long Rxsttime;            /* Time at which we started receiving current file */
  111. static int EMSI_flag;            /* Currently in EMSI-Session ?                     */
  112. static int EMSI_aka;            /* Current aka to send mail to                     */
  113. static int EMSI_raka;            /* Current aka to request files from               */
  114.  
  115. /*****************************************************************************/
  116. /* Super-duper neato-whizbang full-duplex streaming ACKless batch file       */
  117. /* transfer protocol for use in WaZOO mail sessions                          */
  118. /*****************************************************************************/
  119. void 
  120. Janus (void)
  121. {
  122.     byte xstate;                /* Current file transmission state                 */
  123.     byte rstate;                /* Current file reception state                    */
  124.     byte pkttype;                /* Type of packet last received                    */
  125.     byte tx_inhibit;            /* Flag to wait and send after done receiving      */
  126.     char *holdname;                /* Name of hold area                               */
  127.     byte fsent;                    /* Did we manage to send anything this session?    */
  128.     byte sending_req;            /* Are we currently sending requested files?       */
  129.     byte attempting_req;        /* Are we waiting for the sender to start our req? */
  130.     byte req_started;            /* Has the sender started servicing our request?   */
  131.     int txoldeta;                /* Last transmission ETA displayed                 */
  132.     int rxoldeta;                /* Last reception ETA displayed                    */
  133.     word blklen;                /* Length of last data block sent                  */
  134.     word txblklen;                /* Size of data block to try to send this time     */
  135.     word txblkmax;                /* Max size of data block to send at this speed    */
  136.     word goodneeded;            /* # good bytes to send before upping txblklen     */
  137.     word goodbytes;                /* Number of good bytes sent at this block size    */
  138.     word rpos_count;            /* Number of RPOS packets sent at this position    */
  139.     long xmit_retry;            /* Time to retransmit lost FNAMEPKT or EOF packet  */
  140.     long txpos;                    /* Current position within file we're sending      */
  141.     long lasttx;                /* Position within file of last data block we sent */
  142.     long txstpos;                /* Initial data position of file we're sending     */
  143.     long rxstpos;                /* Initial data position of file we're receiving   */
  144.     long txoldpos;                /* Last transmission file position displayed       */
  145.     long rxoldpos;                /* Last reception file position displayed          */
  146.     long rpos_retry;            /* Time at which to retry RPOS packet              */
  147.     long brain_dead;            /* Time at which to give up on other computer      */
  148.     long rpos_sttime = 0;        /* Time at which we started current RPOS sequence  */
  149.     long last_rpostime;            /* Timetag of last RPOS which we performed         */
  150.     long last_blkpos;            /* File position of last out-of-sequence BLKPKT    */
  151.     FILE *reqfile;                /* File handle for .REQ file                       */
  152.  
  153.     sprintf (ReqTmp, ReqTmpTempl, TaskNumber);
  154.  
  155.     set_prior (3);                /* Time Critical             */
  156.     XON_DISABLE ();
  157.     if (un_attended && fullscreen)
  158.     {
  159.         clear_filetransfer ();
  160.         sb_show ();
  161.     }
  162.     else
  163.     {
  164.         set_xy (NULL);
  165.         Next_y = locate_y;
  166.     }
  167.     Tx_y = Rx_y = 0;
  168.     SharedCap = 0;
  169.  
  170.     /*------------------------------------------------------------------------*/
  171.     /* Allocate memory                                                        */
  172.     /*------------------------------------------------------------------------*/
  173.     Rxbuf = (char *) Txbuf + 4096 + 8;
  174.     Txfname = Rxfname = NULL;
  175.     if (((Txfname = malloc (PATHLEN)) == NULL)
  176.         || ((Rxfname = malloc (PATHLEN)) == NULL))
  177.     {
  178.         status_line (MSG_TXT (M_MEM_ERROR));
  179.         mdm_hangup ();
  180.         goto freemem;
  181.     }
  182.     Rxbufmax = (byte *) (Rxbuf + BUFMAX + 8);
  183.  
  184.     /*------------------------------------------------------------------------*/
  185.     /* Initialize file transmission variables                                 */
  186.     /*------------------------------------------------------------------------*/
  187.     if (!no_EMSI_Session)
  188.     {
  189.         EMSI_flag = TRUE;
  190.         EMSI_aka = EMSI_raka = 0;
  191.         called_addr = remote_akas[EMSI_aka];
  192.     }
  193.     else
  194.         EMSI_flag = FALSE;
  195.     tx_inhibit = FALSE;
  196.     last_rpostime = last_blkpos = lasttx = txstpos = rxstpos = xmit_retry = 0L;
  197.     long_set_timer (&brain_dead, 120);
  198.  
  199.     if (cur_baud.rate_value > 9600L)
  200.     {
  201.         TimeoutSecs = 30;
  202.         txblkmax = BUFMAX;
  203.     }
  204.     else
  205.     {
  206.         TimeoutSecs = (unsigned int) (40960L / cur_baud.rate_value);
  207.         if (TimeoutSecs < 30)
  208.             TimeoutSecs = 30;
  209.         txblkmax = (int)cur_baud.rate_value / 300 * 128;
  210.         if (txblkmax > BUFMAX)
  211.             txblkmax = BUFMAX;
  212.     }
  213.  
  214.     txblklen = txblkmax;
  215.     goodbytes = goodneeded = 0;
  216.     Txfile = -1;
  217.     sending_req = fsent = FALSE;
  218.     xstate = XSENDFNAME;
  219.     getfname (INITIAL_XFER);
  220.  
  221.     /*------------------------------------------------------------------------*/
  222.     /* Initialize file reception variables                                    */
  223.     /*------------------------------------------------------------------------*/
  224.     holdname = HoldAreaNameMunge (&called_addr);
  225.     (void) sprintf (Abortlog_name, "%s%s.Z\0", holdname, Hex_Addr_Str (&called_addr));
  226.  
  227.     if ((Diskavail = zfree (CURRENT.sc_Inbound)) <= 0L)
  228.         Diskavail = 0x7FFFFFF;
  229.  
  230.     Rxbufptr = NULL;
  231.     rpos_retry = rpos_count = 0;
  232.     attempting_req = req_started = FALSE;
  233.     rstate = RRCVFNAME;
  234.  
  235.     /*------------------------------------------------------------------------*/
  236.     /* Send and/or receive stuff until we're done with both                   */
  237.     /*------------------------------------------------------------------------*/
  238.     do
  239.     {                            /* while (xstate || rstate)  */
  240.  
  241.         /*---------------------------------------------------------------------*/
  242.         /* If nothing useful (i.e. sending or receiving good data block) has   */
  243.         /* happened within the last 2 minutes, give up in disgust              */
  244.         /*---------------------------------------------------------------------*/
  245.         if (long_time_gone (&brain_dead))
  246.         {
  247.             j_status (MSG_TXT (M_OTHER_DIED));    /* "He's dead, Jim." */
  248.             goto giveup;
  249.         }
  250.  
  251.         /*---------------------------------------------------------------------*/
  252.         /* If we're tired of waiting for an ACK, try again                     */
  253.         /*---------------------------------------------------------------------*/
  254.         if (xmit_retry)
  255.         {
  256.             if (long_time_gone (&xmit_retry))
  257.             {
  258.                 j_message (Tx_y, MSG_TXT (M_TIMEOUT));
  259.                 xmit_retry = 0L;
  260.  
  261.                 switch (xstate)
  262.                 {
  263.                 case XRCVFNACK:
  264.                     xstate = XSENDFNAME;
  265.                     break;
  266.                 case XRCVFRNAKACK:
  267.                     xstate = XSENDFREQNAK;
  268.                     break;
  269.                 case XRCVEOFACK:
  270.                     errno = 0;
  271.                     if (lseek (Txfile, txpos = lasttx, SEEK_SET) == -1L)
  272.                     {
  273.                         (void) j_error (MSG_TXT (M_SEEK_MSG), Txfname);
  274.                         goto giveup;
  275.                     }
  276.                     xstate = XSENDBLK;
  277.                     break;
  278.                 }
  279.             }
  280.         }
  281.  
  282.         /*---------------------------------------------------------------------*/
  283.         /* Transmit next part of file, if any                                  */
  284.         /*---------------------------------------------------------------------*/
  285.         switch (xstate)
  286.         {
  287.         case XSENDBLK:
  288.             if (tx_inhibit)
  289.                 break;
  290. #ifdef GENERIC
  291.             lasttx = txpos;
  292.             Txbuf[0] = txpos & 0xff;
  293.             Txbuf[1] = (txpos >> 8) & 0xff;
  294.             Txbuf[2] = (txpos >> 16) & 0xff;
  295.             Txbuf[3] = (txpos >> 24) & 0xff;
  296. #else
  297.             *((long *) Txbuf) = lasttx = txpos;
  298. #endif
  299.             errno = 0;
  300.             blklen = read (Txfile, Txbuf + sizeof (txpos), txblklen);
  301.             if (j_error (MSG_TXT (M_READ_MSG), Txfname))
  302.                 goto giveup;
  303.             txpos += blklen;
  304.             sendpkt (Txbuf, sizeof (txpos) + blklen, BLKPKT);
  305.             update_status (&txpos, &txoldpos, Txlen - txpos, &txoldeta, Tx_y);
  306.             fsent = TRUE;
  307.             if (txpos >= Txlen || blklen < txblklen)
  308.             {
  309.                 long_set_timer (&xmit_retry, TimeoutSecs);
  310.                 xstate = XRCVEOFACK;
  311.             }
  312.             else
  313.                 long_set_timer (&brain_dead, 120);
  314.  
  315.             if (txblklen < txblkmax && (goodbytes += txblklen) >= goodneeded)
  316.             {
  317.                 txblklen <<= 1;
  318.                 goodbytes = 0;
  319.             }
  320.             break;
  321.  
  322.         case XSENDFNAME:
  323.             blklen = (int) (strchr (strchr ((char *) Txbuf, '\0') + 1, '\0') - (char *) Txbuf) + 1;
  324.             Txbuf[blklen++] = OURCAP;
  325.             sendpkt (Txbuf, blklen, FNAMEPKT);
  326.             txoldpos = txoldeta = -1;
  327.             long_set_timer (&xmit_retry, TimeoutSecs);
  328.             xstate = XRCVFNACK;
  329.             break;
  330.  
  331.         case XSENDFREQNAK:
  332.             sendpkt (NULL, 0, FREQNAKPKT);
  333.             long_set_timer (&xmit_retry, TimeoutSecs);
  334.             xstate = XRCVFRNAKACK;
  335.             break;
  336.         }
  337.  
  338.         /*---------------------------------------------------------------------*/
  339.         /* Catch up on our reading; receive and handle all outstanding packets */
  340.         /*---------------------------------------------------------------------*/
  341.         while ((pkttype = rcvpkt ()) != 0)
  342.         {
  343.             if (pkttype != BADPKT)
  344.                 long_set_timer (&brain_dead, 120);
  345.             switch (pkttype)
  346.             {
  347.  
  348.                 /*---------------------------------------------------------------*/
  349.                 /* File data block or munged block                               */
  350.                 /*---------------------------------------------------------------*/
  351.             case BADPKT:
  352.             case BLKPKT:
  353.                 if (rstate == RRCVBLK)
  354.                 {
  355.                     long t;
  356.  
  357. #ifdef GENERIC
  358.                     t = (long) Rxbuf[0] +
  359.                         ((long) Rxbuf[1] << 8) +
  360.                         ((long) Rxbuf[2] << 16) +
  361.                         ((long) Rxbuf[3] << 24);
  362. #else
  363.                     t = *(long *) Rxbuf;
  364. #endif
  365.                     if (pkttype == BADPKT || (t != Rxpos))
  366.                     {
  367.                         if (pkttype == BLKPKT)
  368.                         {
  369.                             if (t < last_blkpos)
  370.                                 rpos_retry = rpos_count = 0;
  371.                             last_blkpos = t;
  372.                         }
  373.                         if (long_time_gone (&rpos_retry))
  374.                         {
  375.  
  376.                             /*---------------------------------------------------*/
  377.                             /* If we're the called machine, and we're trying to  */
  378.                             /* send stuff, and it seems to be screwing up our    */
  379.                             /* ability to receive stuff, maybe this connection   */
  380.                             /* just can't hack full-duplex.  Try waiting till    */
  381.                             /* the sending system finishes before sending our    */
  382.                             /* stuff to it                                       */
  383.                             /*---------------------------------------------------*/
  384.                             if (rpos_count > 4)
  385.                             {
  386.                                 if (xstate && !isOriginator && !tx_inhibit)
  387.                                 {
  388.                                     tx_inhibit = TRUE;
  389.                                     j_status (MSG_TXT (M_GOING_ONE_WAY));
  390.                                 }
  391.                                 rpos_count = 0;
  392.                             }
  393.                             if (++rpos_count == 1)
  394.                                 (void) time ((time_t *) & rpos_sttime);
  395.                             j_message (Rx_y, MSG_TXT (M_J_BAD_PACKET), Rxpos);
  396. #ifdef GENERIC
  397.                             Rxbuf[0] = Rxpos & 0xff;
  398.                             Rxbuf[1] = (Rxpos >> 8) & 0xff;
  399.                             Rxbuf[2] = (Rxpos >> 16) & 0xff;
  400.                             Rxbuf[3] = (Rxpos >> 24) & 0xff;
  401.                             Rxbuf[4] = rpos_sttime & 0xff;
  402.                             Rxbuf[5] = (rpos_sttime >> 8) & 0xff;
  403.                             Rxbuf[6] = (rpos_sttime >> 16) & 0xff;
  404.                             Rxbuf[7] = (rpos_sttime >> 24) & 0xff;
  405. #else
  406.                             *((long *) Rxbuf) = Rxpos;
  407.                             *((long *) (Rxbuf + sizeof (Rxpos))) = rpos_sttime;
  408. #endif
  409.                             sendpkt ((byte *) Rxbuf, sizeof (Rxpos) + sizeof (rpos_sttime), RPOSPKT);
  410.                             long_set_timer (&rpos_retry, TimeoutSecs / 2);
  411.                         }
  412.                     }
  413.                     else
  414.                     {
  415.                         last_blkpos = Rxpos;
  416.                         rpos_retry = rpos_count = 0;
  417.                         errno = 0;
  418.                         (void) write (Rxfile, Rxbuf + sizeof (Rxpos), Rxblklen -= sizeof (Rxpos));
  419.                         if (j_error (MSG_TXT (M_WRITE_MSG), Rxfname))
  420.                             goto giveup;
  421.                         Diskavail -= Rxblklen;
  422.                         Rxpos += Rxblklen;
  423.                         update_status (&Rxpos, &rxoldpos, Rxlen - Rxpos, &rxoldeta, Rx_y);
  424.                         if (Rxpos >= Rxlen)
  425.                         {
  426.                             long Rxtime;
  427.  
  428.                             rxclose (GOOD_XFER);
  429.                             Rxlen -= rxstpos;
  430.                             Rxtime = through (&Rxlen, &Rxsttime);
  431.                             j_status ("%s-J%s %s", MSG_TXT (M_FILE_RECEIVED), (SharedCap & CANCRC32) ? "/32" : " ", Rxfname);
  432.                             j_msgend (Rx_y);
  433.                             update_files (0, Rxfname, Rxlen, Rxtime, 0);
  434.                             rstate = RRCVFNAME;
  435.                         }
  436.                     }
  437.                 }
  438.                 if (rstate == RRCVFNAME)
  439.                     sendpkt (NULL, 0, EOFACKPKT);
  440.                 break;
  441.  
  442.                 /*---------------------------------------------------------------*/
  443.                 /* Name and other data for next file to receive                  */
  444.                 /*---------------------------------------------------------------*/
  445.             case FNAMEPKT:
  446.                 if (rstate == RRCVFNAME)
  447.                     Rxpos = rxstpos = procfname ();
  448.                 if (!Rxfname[0] && get_filereq (req_started))
  449.                 {
  450.                     sendpkt ((byte *) Rxbuf, strlen (Rxbuf) + 2, FREQPKT);
  451.                     attempting_req = TRUE;
  452.                     req_started = FALSE;
  453.                 }
  454.                 else
  455.                 {
  456.                     if (attempting_req)
  457.                     {
  458.                         attempting_req = FALSE;
  459.                         req_started = TRUE;
  460.                     }
  461. #ifdef GENERIC
  462.                     Rxbuf[0] = Rxpos & 0xff;
  463.                     Rxbuf[1] = (Rxpos >> 8) & 0xff;
  464.                     Rxbuf[2] = (Rxpos >> 16) & 0xff;
  465.                     Rxbuf[3] = (Rxpos >> 24) & 0xff;
  466.                     Rxbuf[4] = SharedCap;
  467. #else
  468.                     *((long *) Rxbuf) = Rxpos;
  469.                     Rxbuf[sizeof (Rxpos)] = (char) SharedCap;
  470. #endif
  471.                     sendpkt ((byte *) Rxbuf, sizeof (Rxpos) + 1, FNACKPKT);
  472.                     rxoldpos = rxoldeta = -1;
  473.                     if (Rxpos > -1)
  474.                         rstate = (byte) ((Rxfname[0]) ? RRCVBLK : RDONE);
  475.                     else
  476.                         j_status (MSG_TXT (M_REFUSING), Rxfname);
  477.                     if (!rstate)
  478.                         tx_inhibit = FALSE;
  479.                     if (!(xstate || rstate))
  480.                         goto breakout;
  481.                 }
  482.                 break;
  483.  
  484.                 /*---------------------------------------------------------------*/
  485.                 /* ACK to filename packet we just sent                           */
  486.                 /*---------------------------------------------------------------*/
  487.             case FNACKPKT:
  488.                 if (xstate == XRCVFNACK)
  489.                 {
  490.                     xmit_retry = 0L;
  491.                     if (Txfname[0])
  492.                     {
  493. #ifdef GENERIC
  494.                         SharedCap = (Rxblklen > sizeof (long)) ? Rxbuf[4] : 0;
  495.  
  496.                         txpos = (long) Rxbuf[0] +
  497.                             ((long) Rxbuf[1] << 8) +
  498.                             ((long) Rxbuf[2] << 16) +
  499.                             ((long) Rxbuf[3] << 24);
  500. #else
  501.                         SharedCap = (byte) ((Rxblklen > sizeof (long)) ? Rxbuf[sizeof (long)] : 0);
  502.  
  503.                         txpos = *((long *) Rxbuf);
  504. #endif
  505.                         if (txpos > -1L)
  506.                         {
  507.                             if (txpos)
  508.                                 status_line (MSG_TXT (M_SYNCHRONIZING), txpos);
  509.                             errno = 0;
  510.                             if (lseek (Txfile, txstpos = txpos, SEEK_SET) == -1L)
  511.                             {
  512.                                 (void) j_error (MSG_TXT (M_SEEK_MSG), Txfname);
  513.                                 goto giveup;
  514.                             }
  515.                             xstate = XSENDBLK;
  516.                         }
  517.                         else
  518.                         {
  519.                             j_status (MSG_TXT (M_REMOTE_REFUSED), Txfname);
  520.                             if (sending_req)
  521.                             {
  522.                                 if (!(sending_req = get_reqname (FALSE)))
  523.                                     getfname (GOOD_XFER);
  524.                             }
  525.                             else
  526.                             {
  527.                                 Do_after = NOTHING_AFTER;
  528.                                 getfname (GOOD_XFER);
  529.                             }
  530.                             xstate = XSENDFNAME;
  531.                         }
  532.                     }
  533.                     else
  534.                     {
  535.                         sent_mail = 1;
  536.                         xstate = XDONE;
  537.                     }
  538.                 }
  539.                 if (!(xstate || rstate))
  540.                     goto breakout;
  541.                 break;
  542.  
  543.                 /*---------------------------------------------------------------*/
  544.                 /* Request to send more stuff rather than end batch just yet     */
  545.                 /*---------------------------------------------------------------*/
  546.             case FREQPKT:
  547.                 if (xstate == XRCVFNACK)
  548.                 {
  549.                     xmit_retry = 0L;
  550.                     SharedCap = *(strchr (Rxbuf, '\0') + 1);
  551.                     (void) sprintf ((char *) Txbuf, request_template, CURRENT.sc_Inbound,
  552.                         Hex_Addr_Str (&(alias[0])), TaskNumber);
  553.                     errno = 0;
  554.                     reqfile = fopen ((char *) Txbuf, write_ascii);
  555.                     if (reqfile != (FILE *) NULL)
  556.                         errno = 0;
  557.                     (void) j_error (MSG_TXT (M_OPEN_MSG), (char *) Txbuf);
  558.                     (void) fputs (Rxbuf, reqfile);
  559.                     (void) fputs ("\n", reqfile);
  560.                     (void) fclose (reqfile);
  561.                     (void) unlink (ReqTmp);
  562.                     ReqRecorded = 0;    /* counted by record_reqfile */
  563.                     (void) respond_to_file_requests (0, record_reqfile, timeof_reqfile);
  564.                     CURRENT.rq_Limit -= ReqRecorded;
  565.                     if ((sending_req = get_reqname (TRUE)) != 0)
  566.                         xstate = XSENDFNAME;
  567.                     else
  568.                         xstate = XSENDFREQNAK;
  569.                 }
  570.                 break;
  571.  
  572.                 /*---------------------------------------------------------------*/
  573.                 /* Our last file request didn't match anything; move on to next  */
  574.                 /*---------------------------------------------------------------*/
  575.             case FREQNAKPKT:
  576.                 attempting_req = FALSE;
  577.                 req_started = TRUE;
  578.                 sendpkt (NULL, 0, FRNAKACKPKT);
  579.                 break;
  580.  
  581.                 /*---------------------------------------------------------------*/
  582.                 /* ACK to no matching files for request error; try to end again  */
  583.                 /*---------------------------------------------------------------*/
  584.             case FRNAKACKPKT:
  585.                 if (xstate == XRCVFRNAKACK)
  586.                 {
  587.                     xmit_retry = 0L;
  588.                     getfname (GOOD_XFER);
  589.                     xstate = XSENDFNAME;
  590.                 }
  591.                 break;
  592.  
  593.                 /*---------------------------------------------------------------*/
  594.                 /* ACK to last data block in file                                */
  595.                 /*---------------------------------------------------------------*/
  596.             case EOFACKPKT:
  597.                 if (xstate == XRCVEOFACK || xstate == XRCVFNACK)
  598.                 {
  599.                     xmit_retry = 0L;
  600.                     if (xstate == XRCVEOFACK)
  601.                     {
  602.                         long    Txtime;
  603.  
  604.                         Txlen -= txstpos;
  605.                         Txtime = through (&Txlen, &Txsttime);
  606.                         j_status ("%s-J%s %s", MSG_TXT (M_FILE_SENT), (SharedCap & CANCRC32) ? "/32" : " ", Txfname);
  607.                         j_msgend (Tx_y);
  608.                         update_files (1, Txfname, Txlen, Txtime, 0);
  609.  
  610.                         if (sending_req)
  611.                         {
  612.                             if (!(sending_req = get_reqname (FALSE)))
  613.                                 getfname (GOOD_XFER);
  614.                         }
  615.                         else
  616.                             getfname (GOOD_XFER);
  617.                     }
  618.                     xstate = XSENDFNAME;
  619.                 }
  620.                 break;
  621.  
  622.                 /*---------------------------------------------------------------*/
  623.                 /* Receiver says "let's try that again."                         */
  624.                 /*---------------------------------------------------------------*/
  625.             case RPOSPKT:
  626.                 if (xstate == XSENDBLK || xstate == XRCVEOFACK)
  627.                 {
  628.                     long t;
  629.  
  630. #ifdef GENERIC
  631.                     t = (long) Rxbuf[4] +
  632.                         ((long) Rxbuf[5] << 8) +
  633.                         ((long) Rxbuf[6] << 16) +
  634.                         ((long) Rxbuf[7] << 24);
  635. #else
  636.                     t = *((long *) (Rxbuf + sizeof (txpos)));
  637. #endif
  638.                     if (t != last_rpostime)
  639.                     {
  640.                         last_rpostime = t;
  641.                         xmit_retry = 0L;
  642.                         CLEAR_OUTBOUND ();
  643.                         errno = 0;
  644. #ifdef GENERIC
  645.                         lasttx = (long) Rxbuf[0] +
  646.                             ((long) Rxbuf[1] << 8) +
  647.                             ((long) Rxbuf[2] << 16) +
  648.                             ((long) Rxbuf[3] << 24);
  649. #else
  650.                         lasttx = *((long *) Rxbuf);
  651. #endif
  652.                         if (lseek (Txfile, txpos = lasttx, SEEK_SET) == -1L)
  653.                         {
  654.                             (void) j_error (MSG_TXT (M_SEEK_MSG), Txfname);
  655.                             goto giveup;
  656.                         }
  657.                         j_status (MSG_TXT (M_SYNCHRONIZING), txpos);
  658.                         txblklen >>= 2;
  659.                         if (txblklen < 64)
  660.                             txblklen = 64;
  661.                         goodbytes = 0;
  662.                         goodneeded += 1024;
  663.                         if (goodneeded > 8192)
  664.                             goodneeded = 8192;
  665.                         xstate = XSENDBLK;
  666.                     }
  667.                 }
  668.                 break;
  669.  
  670.                 /*---------------------------------------------------------------*/
  671.                 /* Debris from end of previous Janus session; ignore it          */
  672.                 /*---------------------------------------------------------------*/
  673.             case HALTACKPKT:
  674.                 break;
  675.  
  676.                 /*---------------------------------------------------------------*/
  677.                 /* Abort the transfer and quit                                   */
  678.                 /*---------------------------------------------------------------*/
  679.             default:
  680.                 j_status (MSG_TXT (M_UNKNOWN_PACKET), pkttype);
  681.  
  682.                 /* fallthrough */
  683.  
  684.             case HALTPKT:
  685. giveup:
  686.                 j_status (MSG_TXT (M_SESSION_ABORT));
  687.                 if (Txfname[0])
  688.                     getfname (ABORT_XFER);
  689.                 if (rstate == RRCVBLK)
  690.                 {
  691.                     rxclose (FAILED_XFER);
  692.                 }
  693.                 goto abortxfer;
  694.  
  695.             }                    /* switch (pkttype)  */
  696.         }                        /* while (pkttype)   */
  697.     }
  698.     while (xstate || rstate);
  699.  
  700.     /*------------------------------------------------------------------------*/
  701.     /* All done; make sure other end is also finished (one way or another)    */
  702.     /*------------------------------------------------------------------------*/
  703. breakout:
  704.  
  705.     if (!fsent)
  706.         j_status (MSG_TXT (M_NOTHING_TO_SEND), Full_Addr_Str (&called_addr));
  707.  
  708. abortxfer:
  709.  
  710.     endbatch ();
  711.  
  712.     /*------------------------------------------------------------------------*/
  713.     /* Release allocated memory                                               */
  714.     /*------------------------------------------------------------------------*/
  715.  
  716. freemem:
  717.  
  718.     if (Txfname)
  719.         free (Txfname);
  720.     if (Rxfname)
  721.         free (Rxfname);
  722.     set_prior (4);                /* Always High                                     */
  723. }
  724.  
  725. /*****************************************************************************/
  726. /* Get name and info for next file to be transmitted, if any, and build      */
  727. /* FNAMEPKT.  Packet contents as per ZModem filename info packet, to allow   */
  728. /* use of same method of aborted-transfer recovery.  If there are no more    */
  729. /* files to be sent, build FNAMEPKT with null filename.  Also open file and  */
  730. /* set up for transmission.  Set Txfname, Txfile, Txlen.  Txbuf must not be  */
  731. /* modified until FNACKPKT is received.                                      */
  732. /*****************************************************************************/
  733. static void LOCALFUNC 
  734. getfname (word xfer_flag)
  735. {
  736.     static byte floflag, bad_xfers;
  737.     static char outboundname[PATHLEN];
  738.     static long floname_pos;
  739.     static FILE *flofile;
  740.     char *holdname;
  741.  
  742.     register char *p;
  743.     int i;
  744.     long curr_pos;
  745.     struct stat f;
  746.  
  747.     /*------------------------------------------------------------------------*/
  748.     /* Initialize static variables on first call of the batch                 */
  749.     /*------------------------------------------------------------------------*/
  750.     if (xfer_flag == INITIAL_XFER)
  751.     {
  752.         if (EMSI_flag)
  753.             status_line (MSG_TXT (M_EMSI_PROC_NODE),
  754.                 Full_Addr_Str (&remote_akas[EMSI_aka]),
  755.                 HoldAreaNameMunge (&remote_akas[EMSI_aka]));
  756.  
  757.         floflag = outboundname[0] = '\0';
  758.         flofile = NULL;
  759.     }
  760.     else
  761.         /*------------------------------------------------------------------------*/
  762.         /* If we were already sending a file, close it and clean up               */
  763.         /*------------------------------------------------------------------------*/
  764.     if (Txfile != -1)
  765.     {
  766.         errno = 0;
  767.         (void) close (Txfile);
  768.         Txfile = -1;
  769.         /*---------------------------------------------------------------------*/
  770.         /* If xfer completed, do post-xfer cleanup                             */
  771.         /*---------------------------------------------------------------------*/
  772.         if (xfer_flag == GOOD_XFER)
  773.         {
  774.             /*------------------------------------------------------------------*/
  775.             /* Perform post-xfer file massaging if neccessary                   */
  776.             /*------------------------------------------------------------------*/
  777.             switch (Do_after)
  778.             {
  779.             case DELETE_AFTER:
  780.             case SHOW_DELETE_AFTER:
  781.                 j_status (MSG_TXT (M_UNLINKING_MSG), Txfname);
  782.                 (void) unlink (Txfname);
  783.                 break;
  784.             case TRUNC_AFTER:
  785.                 j_status (MSG_TXT (M_TRUNC_MSG), Txfname);
  786.                 Txfile = open (Txfname, O_TRUNC | O_RDWR, S_IREAD | S_IWRITE);
  787.                 if (Txfile != -1)
  788.                     errno = 0;
  789.                 (void) j_error (MSG_TXT (M_TRUNC_MSG), Txfname);
  790.                 (void) close (Txfile);
  791.                 Txfile = -1;
  792.             }
  793.             /*------------------------------------------------------------------*/
  794.             /* If processing .?LO file, flag filename as sent (name[0] = '~')   */
  795.             /*------------------------------------------------------------------*/
  796. skipname:
  797.  
  798.             if (floflag)
  799.             {
  800.                 curr_pos = ftell (flofile);
  801.                 if (curr_pos == -1L)
  802.                     (void) j_error (MSG_TXT (M_SEEK_MSG), outboundname);
  803.                 if (fseek (flofile, floname_pos, SEEK_SET) == -1L)
  804.                     (void) j_error (MSG_TXT (M_SEEK_MSG), outboundname);
  805.                 if (fputc (Txfname[0] = '~', flofile) != EOF)
  806.                     errno = 0;
  807.                 (void) j_error (MSG_TXT (M_WRITE_MSG), outboundname);
  808.                 if (fseek (flofile, curr_pos, SEEK_SET) == -1L)
  809.                     (void) j_error (MSG_TXT (M_SEEK_MSG), outboundname);
  810.             }
  811.         }
  812.         else
  813.         {
  814.           abort:
  815.             ++bad_xfers;
  816.         }
  817.     }
  818.  
  819.     /*------------------------------------------------------------------------*/
  820.     /* Find next file to be sent and build FNAMEPKT.  If reading .FLO-type    */
  821.     /* file get next entry from it; otherwise check for next .OUT/.FLO file   */
  822.     /*------------------------------------------------------------------------*/
  823.  
  824.     if (EMSI_flag)
  825.         holdname = HoldAreaNameMunge (&remote_akas[EMSI_aka]);
  826.     else
  827.         holdname = HoldAreaNameMunge (&called_addr);
  828.  
  829. next_aka:
  830.  
  831.     if (!floflag)
  832.     {
  833.         /*---------------------------------------------------------------------*/
  834.         /* If first getfname() for this batch, init filename to .OUT           */
  835.         /*---------------------------------------------------------------------*/
  836.         if (!outboundname[0])
  837.         {
  838.             if (!EMSI_flag)
  839.                 (void) sprintf (outboundname,
  840.                     "%s%s.OUT",
  841.                     holdname,
  842.                     Hex_Addr_Str (&called_addr));
  843.             else
  844.                 (void) sprintf (outboundname,
  845.                     "%s%s.OUT",
  846.                     holdname,
  847.                     Hex_Addr_Str (&remote_akas[EMSI_aka]));
  848.             *ext_flags = 'O';
  849.         }
  850.         /*---------------------------------------------------------------------*/
  851.         /* Increment outbound filename until match found or all checked        */
  852.         /* .OUT->.DUT->.CUT->.HUT->.FLO->.DLO->.CLO->.HLO->null name           */
  853.         /*---------------------------------------------------------------------*/
  854.         else
  855.         {
  856. nxtout:
  857.             p = strchr (outboundname, '\0') - 3;
  858.             for (i = 0; i < NUM_FLAGS; ++i)
  859.                 if (ext_flags[i] == *p)
  860.                     break;
  861.             if (i < NUM_FLAGS - 1)
  862.             {
  863.                 *p = ext_flags[i + 1];
  864. #ifndef JACK_DECKER
  865.                 if (isOriginator && *p == 'H')
  866.                     goto nxtout;
  867. #endif
  868.             }
  869.             else
  870.             {
  871.                 /*---------------------------------------------------------------*/
  872.                 /* Finished ?,D,C,H sequence; wrap .OUT->.FLO, or .FLO->done     */
  873.                 /*---------------------------------------------------------------*/
  874.                 if (!floflag)
  875.                 {
  876.                     *p++ = *ext_flags = 'F';
  877.                     *p++ = 'L';
  878.                     *p = 'O';
  879.                     ++floflag;
  880.                 }
  881.                 else
  882.                 {
  883.                     outboundname[0] = Txfname[0] = Txbuf[0] = Txbuf[1] = floflag = '\0';
  884.                     if (EMSI_flag && (++EMSI_aka < num_rakas))
  885.                     {
  886.                         holdname = HoldAreaNameMunge (&remote_akas[EMSI_aka]);
  887.                         status_line (MSG_TXT (M_EMSI_PROC_NODE),
  888.                             Full_Addr_Str (&remote_akas[EMSI_aka]),
  889.                             holdname);
  890.                         goto next_aka;
  891.                     }
  892.                 }
  893.             }
  894.         }
  895.         /*---------------------------------------------------------------------*/
  896.         /* Check potential outbound name; if file doesn't exist keep looking   */
  897.         /*---------------------------------------------------------------------*/
  898.         if (outboundname[0])
  899.         {
  900.             if (!dexists (outboundname))
  901.                 goto nxtout;
  902.             if (floflag)
  903.                 goto rdflo;
  904.             (void) strcpy (Txfname, outboundname);
  905.             /*------------------------------------------------------------------*/
  906.             /* Start FNAMEPKT using .PKT alias                                  */
  907.             /*------------------------------------------------------------------*/
  908.             invent_pkt_name ((char *) Txbuf);
  909.             Do_after = DELETE_AFTER;
  910.         }
  911.         /*---------------------------------------------------------------------*/
  912.         /* Read and process next entry from .?LO-type file                     */
  913.         /*---------------------------------------------------------------------*/
  914.     }
  915.     else
  916.     {
  917.  
  918. rdflo:
  919.         /*---------------------------------------------------------------------*/
  920.         /* Open .?LO file for processing if neccessary                         */
  921.         /*---------------------------------------------------------------------*/
  922.         if (!flofile)
  923.         {
  924.             bad_xfers = 0;
  925.             errno = 0;
  926.             flofile = share_fopen (outboundname, "rb+", DENY_WRITE);
  927.             if (flofile == (FILE *) NULL)
  928.             {
  929.                 j_error (MSG_TXT (M_OPEN_MSG), outboundname);
  930.                 goto nxtout;
  931.             }
  932.         }
  933.         errno = 0;
  934.         floname_pos = ftell (flofile);
  935.         if (floname_pos == -1L)
  936.             (void) j_error (MSG_TXT (M_SEEK_MSG), outboundname);
  937.         if (fgets (p = Txfname, PATHLEN, flofile))
  938.         {
  939.             /*------------------------------------------------------------------*/
  940.             /* Got an attached file name; check for handling flags, fix up name */
  941.             /*------------------------------------------------------------------*/
  942.             while (*p > ' ')
  943.                 ++p;
  944.             *p = '\0';
  945.             switch (Txfname[0])
  946.             {
  947.             case '\0':
  948.             case '~':
  949.             case ';':
  950.                 goto rdflo;
  951.             case TRUNC_AFTER:
  952.             case DELETE_AFTER:
  953.             case SHOW_DELETE_AFTER:
  954.                 Do_after = Txfname[0];
  955.                 (void) strcpy (Txfname, Txfname + 1);
  956.                 break;
  957.             default:
  958.                 Do_after = NOTHING_AFTER;
  959.                 break;
  960.             }
  961.             /*------------------------------------------------------------------*/
  962.             /* Start FNAMEPKT with simple filename                              */
  963.             /*------------------------------------------------------------------*/
  964.             while (p >= Txfname && *p != '\\' && *p != ':')
  965.                 --p;
  966.             (void) strcpy ((char *) Txbuf, ++p);
  967.         }
  968.         else
  969.         {
  970.             /*------------------------------------------------------------------*/
  971.             /* Finished reading this .?LO file; clean up and look for another   */
  972.             /*------------------------------------------------------------------*/
  973.             errno = 0;
  974.             (void) fclose (flofile);
  975.             flofile = NULL;
  976.             if (!bad_xfers)
  977.             {
  978.                 (void) unlink (outboundname);
  979.             }
  980.             goto nxtout;
  981.         }
  982.     }
  983.  
  984.     /*------------------------------------------------------------------------*/
  985.     /* If we managed to find a valid file to transmit, open it, finish        */
  986.     /* FNAMEPKT, and print nice message for the sysop.                        */
  987.     /*------------------------------------------------------------------------*/
  988.     if (Txfname[0])
  989.     {
  990.         if (xfer_flag == ABORT_XFER)
  991.             goto abort;
  992.         j_status (MSG_TXT (M_SENDING), Txfname);
  993.         errno = 0;
  994.         Txfile = share_open (Txfname, O_RDONLY | O_BINARY, DENY_WRITE);
  995.         if (Txfile != -1)
  996.             errno = 0;
  997.         if (j_error (MSG_TXT (M_OPEN_MSG), Txfname))
  998.             goto skipname;
  999.  
  1000.         if (isatty (Txfile))    /* Check for character devices     */
  1001.         {
  1002.             (void) close (Txfile);    /* return errors if it is the case */
  1003.             errno = 1;
  1004.             (void) j_error (MSG_TXT (M_DEVICE_MSG), Txfname);
  1005.             goto skipname;
  1006.         }
  1007.  
  1008.         (void) stat (Txfname, &f);
  1009. #ifdef ANSI_TIME_T
  1010.         f.st_mtime -= ANSI_TIME_T_DELTA;
  1011. #endif
  1012.         (void) sprintf (strchr ((char *) Txbuf, '\0') + 1, "%lu %lo %o", Txlen = f.st_size, f.st_mtime, f.st_mode);
  1013.  
  1014.         p = strchr (Txfname, '\0');
  1015.         while (p >= Txfname && *p != ':' && *p != '\\')
  1016.             --p;
  1017.         if (!un_attended || !fullscreen)
  1018.             Tx_y = Next_y;
  1019.         else
  1020.             Tx_y = 1;
  1021.         xfer_summary (MSG_TXT (M_SEND), ++p, &Txlen, Tx_y);
  1022.  
  1023.         (void) time ((time_t *) & Txsttime);
  1024.     }
  1025. }
  1026.  
  1027. /*****************************************************************************/
  1028. /* Build and send a packet of any type.                                      */
  1029. /* Packet structure is: PKTSTRT,contents,packet_type,PKTEND,crc              */
  1030. /* CRC is computed from contents and packet_type only; if PKTSTRT or PKTEND  */
  1031. /* get munged we'll never even find the CRC.                                 */
  1032. /*****************************************************************************/
  1033. static void LOCALFUNC 
  1034. sendpkt (register byte * buf, int len, int type)
  1035. {
  1036.     register word crc;
  1037.  
  1038.     if ((SharedCap & CANCRC32) && type != FNAMEPKT)
  1039.         sendpkt32 (buf, len, type);
  1040.     else
  1041.     {
  1042.         BUFFER_BYTE (DLE);
  1043.         BUFFER_BYTE (PKTSTRTCHR ^ 0x40);
  1044.  
  1045.         crc = 0;
  1046.         while (--len >= 0)
  1047.         {
  1048.             txbyte (*buf);
  1049.             crc = xcrc (crc, ((word) (*buf++)));
  1050.         }
  1051.  
  1052.         BUFFER_BYTE ((byte) type);
  1053.         crc = xcrc (crc, type);
  1054.  
  1055.         BUFFER_BYTE (DLE);
  1056.         BUFFER_BYTE (PKTENDCHR ^ 0x40);
  1057.  
  1058.         txbyte ((byte) (crc >> 8));
  1059.         txbyte ((byte) (crc & 0xFF));
  1060.  
  1061.         UNBUFFER_BYTES ();
  1062.     }
  1063. }
  1064.  
  1065. /*****************************************************************************/
  1066. /* Build and send a packet using 32-bit CRC; same as sendpkt in other ways   */
  1067. /*****************************************************************************/
  1068. static void LOCALFUNC 
  1069. sendpkt32 (register byte * buf, register int len, int type)
  1070. {
  1071.     unsigned long crc32;
  1072.  
  1073.     BUFFER_BYTE (DLE);
  1074.     BUFFER_BYTE (PKTSTRTCHR32 ^ 0x40);
  1075.  
  1076.     crc32 = 0xFFFFFFFF;
  1077.     while (--len >= 0)
  1078.     {
  1079.         txbyte (*buf);
  1080.         crc32 = Z_32UpdateCRC (((word) * buf), crc32);
  1081.         ++buf;
  1082.     }
  1083.  
  1084.     BUFFER_BYTE ((byte) type);
  1085.     crc32 = Z_32UpdateCRC (type, crc32);
  1086.  
  1087.     BUFFER_BYTE (DLE);
  1088.     BUFFER_BYTE (PKTENDCHR ^ 0x40);
  1089.  
  1090.     txbyte ((byte) (crc32 >> 24));
  1091.     txbyte ((byte) ((crc32 >> 16) & 0xFF));
  1092.     txbyte ((byte) ((crc32 >> 8) & 0xFF));
  1093.     txbyte ((byte) (crc32 & 0xFF));
  1094.  
  1095.     UNBUFFER_BYTES ();
  1096. }
  1097.  
  1098. /*****************************************************************************/
  1099. /* Transmit cooked escaped byte(s) corresponding to raw input byte.  Escape  */
  1100. /* DLE, XON, and XOFF using DLE prefix byte and ^ 0x40. Also escape          */
  1101. /* CR-after-'@' to avoid Telenet/PC-Pursuit problems.                        */
  1102. /*****************************************************************************/
  1103. static void LOCALFUNC 
  1104. txbyte (register byte c)
  1105. {
  1106.     static byte lastsent;
  1107.  
  1108.     switch (c)
  1109.     {
  1110.     case CR:
  1111.         if (lastsent != '@')
  1112.             goto sendit;
  1113.  
  1114.         /* fallthrough */
  1115.  
  1116.     case DLE:
  1117.     case XON:
  1118.     case XOFF:
  1119.         BUFFER_BYTE (DLE);
  1120.         c ^= 0x40;
  1121.  
  1122.         /* fallthrough */
  1123.  
  1124.     default:
  1125.  
  1126. sendit:
  1127.  
  1128.         BUFFER_BYTE (lastsent = c);
  1129.     }
  1130. }
  1131.  
  1132. /*****************************************************************************/
  1133. /* Process FNAMEPKT of file to be received.  Check for aborted-transfer      */
  1134. /* recovery and solve filename collisions.    Check for enough disk space.   */
  1135. /* Return initial file data position to start receiving at, or -1 if error   */
  1136. /* detected to abort file reception.  Set Rxfname, Rxlen, Rxfile.            */
  1137. /*****************************************************************************/
  1138. static long LOCALFUNC 
  1139. procfname (void)
  1140. {
  1141.     register char *p;
  1142.     char linebuf[128], *fileinfo, *badfname;
  1143.     long filestart, bytes;
  1144.     FILE *abortlog;
  1145.     struct stat f;
  1146.     int i;
  1147.  
  1148.     /*------------------------------------------------------------------------*/
  1149.     /* Initialize for file reception                                          */
  1150.     /*------------------------------------------------------------------------*/
  1151.     badfname = NULL;
  1152.     Rxfname[0] = Resume_WaZOO = 0;
  1153.  
  1154.     /*------------------------------------------------------------------------*/
  1155.     /* Save info on WaZOO transfer in case of abort                           */
  1156.     /*------------------------------------------------------------------------*/
  1157.     (void) strcpy (Resume_name, fancy_str (Rxbuf));
  1158.     fileinfo = strchr (Rxbuf, '\0') + 1;
  1159.     p = strchr (fileinfo, '\0') + 1;
  1160.     SharedCap = (byte) ((Rxblklen > p - Rxbuf) ? *p & OURCAP : 0);
  1161.  
  1162.     /*------------------------------------------------------------------------*/
  1163.     /* If this is a null FNAMEPKT, return OK immediately                      */
  1164.     /*------------------------------------------------------------------------*/
  1165.     if (!Rxbuf[0])
  1166.         return 0L;
  1167.  
  1168.     p = Rxbuf + strlen ((char *) Rxbuf) - 1;    /* Find transmitted simple
  1169.                                                   * filename */
  1170.  
  1171.     while (p >= Rxbuf && *p != '\\' && *p != '/' && *p != ':')
  1172.         p--;
  1173.  
  1174.     (void) strcpy (linebuf, ++p);
  1175.     (void) strlwr (linebuf);
  1176.     p = check_netfile (linebuf);
  1177.     j_status ("#%s %s %s", MSG_TXT (M_RECEIVING), (p) ? p : " ", Rxbuf);
  1178.  
  1179.     /*------------------------------------------------------------------------*/
  1180.     /* Extract and validate filesize                                          */
  1181.     /*------------------------------------------------------------------------*/
  1182.     Rxlen = -1;
  1183.     Rxfiletime = 0;
  1184.     if (sscanf (fileinfo, "%ld %lo", &Rxlen, &Rxfiletime) < 1 || Rxlen < 0)
  1185.     {
  1186.         j_status (MSG_TXT (M_NO_LENGTH));
  1187.         return -1L;
  1188.     }
  1189.  
  1190. #ifdef ANSI_TIME_T
  1191.     Rxfiletime += ANSI_TIME_T_DELTA;
  1192. #endif
  1193.  
  1194.     (void) sprintf (Resume_info, "%ld %lo", Rxlen, Rxfiletime);
  1195.  
  1196.     /*------------------------------------------------------------------------*/
  1197.     /* Check if this is a failed WaZOO transfer which should be resumed       */
  1198.     /*------------------------------------------------------------------------*/
  1199.     if (dexists (Abortlog_name))
  1200.     {
  1201.         errno = 0;
  1202.         abortlog = fopen (Abortlog_name, read_ascii);
  1203.         if (abortlog != (FILE *) NULL)
  1204.             errno = 0;
  1205.         if (!j_error (MSG_TXT (M_OPEN_MSG), Abortlog_name))
  1206.         {
  1207.             while (!feof (abortlog))
  1208.             {
  1209.                 linebuf[0] = '\0';
  1210.                 if (!fgets (p = linebuf, sizeof (linebuf), abortlog))
  1211.                     break;
  1212.                 while (*p >= ' ')
  1213.                     ++p;
  1214.                 *p = '\0';
  1215.                 p = strchr (linebuf, ' ');
  1216.                 *p = '\0';
  1217.                 if (!stricmp (linebuf, Resume_name))
  1218.                 {
  1219.                     p = strchr ((badfname = ++p), ' ');
  1220.                     *p = '\0';
  1221.                     if (!stricmp (++p, Resume_info))
  1222.                     {
  1223.                         ++Resume_WaZOO;
  1224.                         break;
  1225.                     }
  1226.                 }
  1227.             }
  1228.             errno = 0;
  1229.             (void) fclose (abortlog);
  1230.         }
  1231.     }
  1232.  
  1233.     /*------------------------------------------------------------------------*/
  1234.     /* Open either the old or a new file, as appropriate                      */
  1235.     /*------------------------------------------------------------------------*/
  1236.     p = strchr (strcpy (Rxfname, CURRENT.sc_Inbound), '\0');
  1237.     errno = 0;
  1238.     if (Resume_WaZOO)
  1239.     {
  1240.         (void) strcpy (p, badfname);
  1241.         Rxfile = open (Rxfname, O_CREAT | O_RDWR | O_BINARY, S_IREAD | S_IWRITE);
  1242.     }
  1243.     else
  1244.     {
  1245.         (void) strcpy (p, Rxbuf);
  1246.         /*---------------------------------------------------------------------*/
  1247.         /* If the file already exists:                                         */
  1248.         /* 1) And the new file has the same time and size, skip it             */
  1249.         /* 2) And OVERWRITE is turned on, delete the old copy                  */
  1250.         /* 3) Else create a unique file name in which to store new data        */
  1251.         /*---------------------------------------------------------------------*/
  1252.         if (dexists (Rxfname))
  1253.         {
  1254.             (void) stat (Rxfname, &f);
  1255.             if (Rxlen == f.st_size && (time_t) Rxfiletime == f.st_mtime)
  1256.             {
  1257.                 j_status (MSG_TXT (M_ALREADY_HAVE), Rxfname);
  1258.                 return -1L;
  1259.             }
  1260.             i = strlen (Rxfname) - 1;
  1261.             if ((!overwrite) || (is_arcmail (Rxfname, i)))
  1262.             {
  1263.                 unique_name (Rxfname);
  1264.                 j_status (MSG_TXT (M_RENAME_MSG), Rxfname);
  1265.             }
  1266.             else
  1267.             {
  1268.                 (void) unlink (Rxfname);
  1269.             }
  1270.         }
  1271.         Rxfile = open (Rxfname, O_CREAT | O_EXCL | O_RDWR | O_BINARY, S_IREAD | S_IWRITE);
  1272.     }
  1273.     if (Rxfile != -1)
  1274.         errno = 0;
  1275.     if (j_error (MSG_TXT (M_OPEN_MSG), Rxfname))
  1276.         return -1L;
  1277.  
  1278.     if (isatty (Rxfile))        /* Check for character devices     */
  1279.     {
  1280.         (void) close (Rxfile);    /* Return errors if it is the case */
  1281.         errno = 1;
  1282.         (void) j_error (MSG_TXT (M_DEVICE_MSG), Rxfname);
  1283.         return -1L;
  1284.     }
  1285.  
  1286.     /*------------------------------------------------------------------------*/
  1287.     /* Determine initial file data position                                   */
  1288.     /*------------------------------------------------------------------------*/
  1289.     if (Resume_WaZOO)
  1290.     {
  1291.         (void) stat (Rxfname, &f);
  1292.         j_status (MSG_TXT (M_SYNCHRONIZING_OFFSET), filestart = f.st_size);
  1293.         p = Rxbuf;
  1294.         errno = 0;
  1295.         if (lseek (Rxfile, filestart, SEEK_SET) == -1L)
  1296.         {
  1297.             (void) j_error (MSG_TXT (M_SEEK_MSG), Rxfname);
  1298.             (void) close (Rxfile);
  1299.             return -1L;
  1300.         }
  1301.     }
  1302.     else
  1303.         filestart = 0L;
  1304.  
  1305.     /*------------------------------------------------------------------------*/
  1306.     /* Check for enough disk space                                            */
  1307.     /*------------------------------------------------------------------------*/
  1308.     bytes = Rxlen - filestart + 10240;
  1309.     if (bytes > Diskavail)
  1310.     {
  1311.         j_status (MSG_TXT (M_OUT_OF_DISK_SPACE));
  1312.         (void) close (Rxfile);
  1313.         return -1L;
  1314.     }
  1315.  
  1316.     /*------------------------------------------------------------------------*/
  1317.     /* Print status message for the sysop                                     */
  1318.     /*------------------------------------------------------------------------*/
  1319.     if (!un_attended || !fullscreen)
  1320.         Rx_y = Next_y;
  1321.     else
  1322.         Rx_y = 2;
  1323.     xfer_summary (MSG_TXT (M_RECV), p, &Rxlen, Rx_y);
  1324.  
  1325.     (void) time ((time_t *) & Rxsttime);
  1326.  
  1327.     return filestart;
  1328. }
  1329.  
  1330. /*****************************************************************************/
  1331. /* Receive, validate, and extract a packet if available.  If a complete      */
  1332. /* packet hasn't been received yet, receive and store as much of the next    */
  1333. /* packet as possible.    Each call to rcvpkt() will continue accumulating a */
  1334. /* packet until a complete packet has been received or an error is detected. */
  1335. /* Rxbuf must not be modified between calls to rcvpkt() if NOPKT is returned.*/
  1336. /* Returns type of packet received, NOPKT, or BADPKT.  Sets Rxblklen.        */
  1337. /*****************************************************************************/
  1338. static byte LOCALFUNC 
  1339. rcvpkt ()
  1340. {
  1341.     static byte rxcrc32;
  1342.     static word crc;
  1343.     static unsigned long crc32;
  1344.     register byte *p;
  1345.     register int c;
  1346.     int i;
  1347.     unsigned long pktcrc;
  1348.  
  1349.     /*------------------------------------------------------------------------*/
  1350.     /* Abort transfer if operator pressed ESC                                 */
  1351.     /*------------------------------------------------------------------------*/
  1352.  
  1353.     if (got_ESC ())
  1354.     {
  1355.         j_status (GenericError, MSG_TXT (M_KBD_MSG));
  1356.         return HALTPKT;
  1357.     }
  1358.  
  1359.     /*------------------------------------------------------------------------*/
  1360.     /* If not accumulating packet yet, find start of next packet              */
  1361.     /*------------------------------------------------------------------------*/
  1362.     WaitFlag = FALSE;
  1363.     p = Rxbufptr;
  1364.     if (!p)
  1365.     {
  1366.         do
  1367.             c = rxbyte ();
  1368.         while (c >= 0 || c == PKTEND);
  1369.  
  1370.         switch (c)
  1371.         {
  1372.         case PKTSTRT:
  1373.             rxcrc32 = FALSE;
  1374.             p = (byte *) Rxbuf;
  1375.             crc = 0;
  1376.             break;
  1377.         case PKTSTRT32:
  1378.             rxcrc32 = TRUE;
  1379.             p = (byte *) Rxbuf;
  1380.             crc32 = 0xFFFFFFFF;
  1381.             break;
  1382.         case NOCARRIER:
  1383.             j_status (GenericError, &(MSG_TXT (M_NO_CARRIER)[1]));
  1384.             return HALTPKT;
  1385.         default:
  1386.             return NOPKT;
  1387.         }
  1388.     }
  1389.  
  1390.     /*------------------------------------------------------------------------*/
  1391.     /* Accumulate packet data until we empty buffer or find packet delimiter  */
  1392.     /*------------------------------------------------------------------------*/
  1393.     if (rxcrc32)
  1394.     {
  1395.         while ((c = rxbyte ()) >= 0 && p < Rxbufmax)
  1396.         {
  1397.             *p++ = (byte) c;
  1398.             crc32 = Z_32UpdateCRC (c, crc32);
  1399.         }
  1400.     }
  1401.     else
  1402.     {
  1403.         while ((c = rxbyte ()) >= 0 && p < Rxbufmax)
  1404.         {
  1405.             *p++ = (byte) c;
  1406.             crc = xcrc (crc, c);
  1407.         }
  1408.     }
  1409.  
  1410.     /*------------------------------------------------------------------------*/
  1411.     /* Handle whichever end-of-packet condition occurred                      */
  1412.     /*------------------------------------------------------------------------*/
  1413.     switch (c)
  1414.     {
  1415.         /*---------------------------------------------------------------------*/
  1416.         /* PKTEND found; verify valid CRC                                      */
  1417.         /*---------------------------------------------------------------------*/
  1418.     case PKTEND:
  1419.         WaitFlag = TRUE;
  1420.         pktcrc = 0;
  1421.         for (i = (rxcrc32) ? 4 : 2; i; --i)
  1422.         {
  1423.             if ((c = rxbyte ()) < 0)
  1424.                 break;
  1425.             pktcrc = (pktcrc << 8) | c;
  1426.         }
  1427.         if (!i)
  1428.         {
  1429.             if ((rxcrc32 && pktcrc == crc32) || pktcrc == crc)
  1430.             {
  1431.                 /*------------------------------------------------------------*/
  1432.                 /* Good packet verified; compute packet data length and       */
  1433.                 /* return packet type                                         */
  1434.                 /*------------------------------------------------------------*/
  1435.                 Rxbufptr = NULL;
  1436.                 Rxblklen = (int) (--p - (byte *) Rxbuf);
  1437.                 return *p;
  1438.             }
  1439.         }
  1440.  
  1441.         /* fallthrough */
  1442.  
  1443.         /*---------------------------------------------------------------------*/
  1444.         /* Bad CRC, carrier lost, or buffer overflow from munged PKTEND        */
  1445.         /*---------------------------------------------------------------------*/
  1446.     default:
  1447.         if (c == NOCARRIER)
  1448.         {
  1449.             j_status (GenericError, &(MSG_TXT (M_NO_CARRIER)[1]));
  1450.             return HALTPKT;
  1451.         }
  1452.         else
  1453.         {
  1454.             Rxbufptr = NULL;
  1455.             return BADPKT;
  1456.         }
  1457.  
  1458.         /*---------------------------------------------------------------------*/
  1459.         /* Emptied buffer; save partial packet and let sender do something     */
  1460.         /*---------------------------------------------------------------------*/
  1461.     case BUFEMPTY:
  1462.         time_release ();        /* Also give other tasks a chance */
  1463.         Rxbufptr = p;
  1464.         return NOPKT;
  1465.  
  1466.         /*---------------------------------------------------------------------*/
  1467.         /* PKTEND was trashed; discard partial packet and prep for next one    */
  1468.         /*---------------------------------------------------------------------*/
  1469.     case PKTSTRT:
  1470.         rxcrc32 = FALSE;
  1471.         Rxbufptr = (byte *) Rxbuf;
  1472.         crc = 0;
  1473.         return BADPKT;
  1474.  
  1475.     case PKTSTRT32:
  1476.         rxcrc32 = TRUE;
  1477.         Rxbufptr = (byte *) Rxbuf;
  1478.         crc32 = 0xFFFFFFFF;
  1479.         return BADPKT;
  1480.     }
  1481. }
  1482.  
  1483. /*****************************************************************************/
  1484. /* Close file being received and perform post-reception aborted-transfer     */
  1485. /* recovery cleanup if neccessary.                                           */
  1486. /*****************************************************************************/
  1487. static void LOCALFUNC 
  1488. rxclose (word xfer_flag)
  1489. {
  1490.     register char *p;
  1491.     char namebuf[PATHLEN], linebuf[128];
  1492.     byte c;
  1493.     FILE *abortlog, *newlog;
  1494.     struct utimbuf utimes;
  1495.  
  1496.     /*------------------------------------------------------------------------*/
  1497.     /* Close file we've been receiving                                        */
  1498.     /*------------------------------------------------------------------------*/
  1499.     errno = 0;
  1500.     (void) close (Rxfile);
  1501.     if (Rxfiletime > 0) /* utime doesn't like negative numbers */
  1502.     {
  1503.         utimes.UT_ACTIME = Rxfiletime;
  1504.         utimes.modtime = Rxfiletime;
  1505.         (void) utime (Rxfname, (UTIMBUF *) & utimes);
  1506.     }
  1507.  
  1508.     /*------------------------------------------------------------------------*/
  1509.     /* If we completed a previously-aborted transfer, kill log entry & rename */
  1510.     /*------------------------------------------------------------------------*/
  1511.     if (xfer_flag == GOOD_XFER && Resume_WaZOO)
  1512.     {
  1513.         abortlog = fopen (Abortlog_name, read_ascii);
  1514.         if (abortlog != (FILE *) NULL)
  1515.             errno = 0;
  1516.         if (!j_error (MSG_TXT (M_OPEN_MSG), Abortlog_name))
  1517.         {
  1518.             c = 0;
  1519.             (void) strcpy (strchr (strcpy (namebuf, Abortlog_name), '\0') - 1, "TMP");
  1520.             newlog = fopen (namebuf, write_ascii);
  1521.             if (newlog != (FILE *) NULL)
  1522.                 errno = 0;
  1523.             if (!j_error (MSG_TXT (M_OPEN_MSG), namebuf))
  1524.             {
  1525.                 while (!feof (abortlog))
  1526.                 {
  1527.                     linebuf[0] = '\0';
  1528.                     if (!fgets (p = linebuf, sizeof (linebuf), abortlog))
  1529.                         break;
  1530.                     while (*p > ' ')
  1531.                         ++p;
  1532.                     *p = '\0';
  1533.                     if (stricmp (linebuf, Resume_name))
  1534.                     {
  1535.                         *p = ' ';
  1536.                         (void) fputs (linebuf, newlog);
  1537.                         if (j_error (MSG_TXT (M_WRITE_MSG), namebuf))
  1538.                             break;
  1539.                         ++c;
  1540.                     }
  1541.                 }
  1542.                 errno = 0;
  1543.                 (void) fclose (abortlog);
  1544.                 (void) fclose (newlog);
  1545.                 (void) unlink (Abortlog_name);
  1546.                 if (c)
  1547.                 {
  1548.                     if (!rename (namebuf, Abortlog_name))
  1549.                         errno = 0;
  1550.                     (void) j_error (MSG_TXT (M_RENAME_MSG), namebuf);
  1551.                 }
  1552.                 else
  1553.                 {
  1554.                     (void) unlink (namebuf);
  1555.                 }
  1556.             }
  1557.             else
  1558.             {
  1559.                 (void) fclose (abortlog);
  1560.             }
  1561.         }
  1562.         j_status (MSG_TXT (M_FINISHED_PART), Resume_name);
  1563.         unique_name (strcat (strcpy (namebuf, CURRENT.sc_Inbound), Resume_name));
  1564.         if (!rename (Rxfname, namebuf))
  1565.         {
  1566.             errno = 0;
  1567.             (void) strcpy (Rxfname, namebuf);
  1568.         }
  1569.         else
  1570.             (void) j_error (MSG_TXT (M_RENAME_MSG), Rxfname);
  1571.         /*------------------------------------------------------------------------*/
  1572.         /* If transfer failed and was not an attempted resumption, log for later  */
  1573.         /*------------------------------------------------------------------------*/
  1574.     }
  1575.     else if (xfer_flag == FAILED_XFER && !Resume_WaZOO)
  1576.     {
  1577.         j_status (MSG_TXT (M_SAVING_PART), Rxfname);
  1578.         unique_name (strcat (strcpy (namebuf, CURRENT.sc_Inbound), "BadWaZOO.001"));
  1579.         if (!rename (Rxfname, namebuf))
  1580.             errno = 0;
  1581.         (void) j_error (MSG_TXT (M_RENAME_MSG), Rxfname);
  1582.  
  1583.         abortlog = fopen (Abortlog_name, append_ascii);
  1584.         if (abortlog != (FILE *) NULL)
  1585.             errno = 0;
  1586.         if (!j_error (MSG_TXT (M_OPEN_MSG), Abortlog_name))
  1587.         {
  1588.             (void) fprintf (abortlog, "%s %s %s\n", Resume_name, namebuf + strlen (CURRENT.sc_Inbound), Resume_info);
  1589.             (void) j_error (MSG_TXT (M_WRITE_MSG), Abortlog_name);
  1590.             (void) fclose (abortlog);
  1591.         }
  1592.         else
  1593.         {
  1594.             (void) unlink (namebuf);
  1595.         }
  1596.     }
  1597. }
  1598.  
  1599. /*****************************************************************************/
  1600. /* Try REAL HARD to disengage batch session cleanly                          */
  1601. /*****************************************************************************/
  1602. static void LOCALFUNC 
  1603. endbatch (void)
  1604. {
  1605.     register int done, timeouts;
  1606.     long timeval, brain_dead;
  1607.  
  1608.     /*------------------------------------------------------------------------*/
  1609.     /* Tell the other end to halt if it hasn't already                        */
  1610.     /*------------------------------------------------------------------------*/
  1611.     done = timeouts = 0;
  1612.     long_set_timer (&brain_dead, 120);
  1613.     sendpkt (NULL, 0, HALTPKT);
  1614.     long_set_timer (&timeval, TimeoutSecs);
  1615.  
  1616.     /*------------------------------------------------------------------------*/
  1617.     /* Wait for the other end to acknowledge that it's halting                */
  1618.     /*------------------------------------------------------------------------*/
  1619.     while (!done)
  1620.     {
  1621.         if (long_time_gone (&brain_dead))
  1622.             break;
  1623.  
  1624.         switch (rcvpkt ())
  1625.         {
  1626.         case NOPKT:
  1627.         case BADPKT:
  1628.             if (long_time_gone (&timeval))
  1629.             {
  1630.                 if (++timeouts > 2)
  1631.                     ++done;
  1632.                 else
  1633.                     goto reject;
  1634.             }
  1635.             break;
  1636.  
  1637.         case HALTPKT:
  1638.         case HALTACKPKT:
  1639.             ++done;
  1640.             break;
  1641.  
  1642.         default:
  1643.             timeouts = 0;
  1644. reject:
  1645.             sendpkt (NULL, 0, HALTPKT);
  1646.             long_set_timer (&timeval, TimeoutSecs);
  1647.             break;
  1648.         }
  1649.     }
  1650.  
  1651.     /*------------------------------------------------------------------------*/
  1652.     /* Announce quite insistently that we're done now                         */
  1653.     /*------------------------------------------------------------------------*/
  1654.     for (done = 0; done < 10; ++done)
  1655.         sendpkt (NULL, 0, HALTACKPKT);
  1656.  
  1657.     while (!OUT_EMPTY())
  1658.         time_release ();
  1659. }
  1660.  
  1661. /*****************************************************************************/
  1662. /* Print a message in the message field of a transfer status line            */
  1663. /*****************************************************************************/
  1664. void 
  1665. j_message (unsigned int pos, char *va_alist,...)
  1666. {
  1667.     va_list arg_ptr;
  1668.     short y, l;
  1669.  
  1670.     char buf[128];
  1671.  
  1672.     y = pos;
  1673.     va_start (arg_ptr, va_alist);
  1674.  
  1675.     if (!un_attended || !fullscreen)
  1676.         gotoxy (MSG_X, y);
  1677.     else
  1678.         sb_move (filewin, y, MSG_X);
  1679.  
  1680.     (void) vsprintf (buf, va_alist, arg_ptr);
  1681.  
  1682.     for (l = 25 - strlen (buf); l > 0; --l)
  1683.         (void) strcat (buf, " ");
  1684.  
  1685.     if (!un_attended || !fullscreen)
  1686.     {
  1687.         (void) cputs (buf);
  1688.     }
  1689.     else
  1690.     {
  1691.         sb_puts (filewin, buf);
  1692.         sb_show ();
  1693.     }
  1694.  
  1695.     va_end (arg_ptr);
  1696. }
  1697.  
  1698. /*****************************************************************************/
  1699. /* Clear out a line in the log status display                                */
  1700. /*****************************************************************************/
  1701.  
  1702. void 
  1703. j_msgend (short pos)
  1704. {
  1705.  
  1706.     if (un_attended && fullscreen)
  1707.     {
  1708.         sb_move (filewin, pos, 2);
  1709.         /* 72 blanks */
  1710.         sb_puts (filewin, "                                                                        ");
  1711.         sb_show ();
  1712.     }
  1713. }
  1714.  
  1715. /*****************************************************************************/
  1716. /* Print & log status message without messing up display                     */
  1717. /*****************************************************************************/
  1718. void 
  1719. j_status (char *va_alist,...)
  1720. {
  1721.     va_list arg_ptr;
  1722.  
  1723.     char buf[128];
  1724.  
  1725.     va_start (arg_ptr, va_alist);
  1726.  
  1727.     if (!un_attended || !fullscreen)
  1728.         gotoxy (1, Next_y - 1);
  1729.  
  1730.     (void) vsprintf (buf, va_alist, arg_ptr);
  1731.  
  1732.     status_line (buf);
  1733.  
  1734.     if (!un_attended || !fullscreen)
  1735.         update_y ();
  1736.  
  1737.     va_end (arg_ptr);
  1738. }
  1739.  
  1740. /*****************************************************************************/
  1741. /* Print & log error message without messing up display                      */
  1742. /*****************************************************************************/
  1743. int 
  1744. j_error (char *msg, char *fname)
  1745. {
  1746.     register int e;
  1747.  
  1748.     if ((e = (int) errno) != 0)
  1749.     {
  1750.  
  1751.         if (!un_attended || !fullscreen)
  1752.             gotoxy (1, Next_y - 1);
  1753.  
  1754.         (void) got_error (msg, fname);
  1755.  
  1756.         if (!un_attended || !fullscreen)
  1757.             update_y ();
  1758.     }
  1759.     return e;
  1760. }
  1761.  
  1762. /*****************************************************************************/
  1763. /* Update screen position variables after printing a message                 */
  1764. /*****************************************************************************/
  1765. static void LOCALFUNC 
  1766. update_y ()
  1767. {
  1768.  
  1769.     set_xy (NULL);                /* Bump cursor to next line after printing   */
  1770.     if (locate_y == Next_y)
  1771.     {                            /* If we didn't go anywhere, screen scrolled;*/
  1772.         if (Tx_y > 1)            /* so decrement status line numbers          */
  1773.             --Tx_y;
  1774.         if (Rx_y > 1)
  1775.             --Rx_y;
  1776.     }
  1777.     else
  1778.         Next_y = locate_y;
  1779. }
  1780.  
  1781. /*****************************************************************************/
  1782. /* Compute future timehack for later reference                               */
  1783. /*****************************************************************************/
  1784. static void LOCALFUNC 
  1785. long_set_timer (long *Buffer, unsigned int Duration)
  1786. {
  1787.  
  1788.     (void) time ((time_t *) Buffer);
  1789.     *Buffer += (long) Duration;
  1790. }
  1791.  
  1792. /*****************************************************************************/
  1793. /* Return TRUE if timehack has been passed, FALSE if not                     */
  1794. /*****************************************************************************/
  1795. static int LOCALFUNC 
  1796. long_time_gone (long *TimePtr)
  1797. {
  1798.  
  1799.     return (time (NULL) > (time_t) * TimePtr);
  1800. }
  1801.  
  1802. /*****************************************************************************/
  1803. /* Receive cooked escaped byte translated to avoid various problems.         */
  1804. /* Returns raw byte, BUFEMPTY, PKTSTRT, PKTEND, or NOCARRIER.                */
  1805. /*****************************************************************************/
  1806. static int LOCALFUNC 
  1807. rxbyte (void)
  1808. {
  1809.     register int c, w;
  1810.  
  1811.     if ((c = rcvrawbyte ()) == DLE)
  1812.     {
  1813.         w = WaitFlag++;
  1814.         if ((c = rcvrawbyte ()) >= 0)
  1815.         {
  1816.             switch (c ^= 0x40)
  1817.             {
  1818.             case PKTSTRTCHR:
  1819.                 c = PKTSTRT;
  1820.                 break;
  1821.             case PKTSTRTCHR32:
  1822.                 c = PKTSTRT32;
  1823.                 break;
  1824.             case PKTENDCHR:
  1825.                 c = PKTEND;
  1826.                 break;
  1827.             }
  1828.         }
  1829.         WaitFlag = (byte) w;
  1830.     }
  1831.     return c;
  1832. }
  1833.  
  1834. /*****************************************************************************/
  1835. /* Receive raw non-escaped byte.  Returns byte, BUFEMPTY, or NOCARRIER.      */
  1836. /* If waitflag is true, will wait for a byte for Timeoutsecs; otherwise      */
  1837. /* will return BUFEMPTY if a byte isn't ready and waiting in inbound buffer. */
  1838. /*****************************************************************************/
  1839. static int LOCALFUNC 
  1840. rcvrawbyte (void)
  1841. {
  1842.     long timeval;
  1843.  
  1844.     if ((int) PEEKBYTE () >= 0)
  1845.         return MODEM_IN ();
  1846.  
  1847.     if (!CARRIER)
  1848.         return NOCARRIER;
  1849.     if (!WaitFlag)
  1850.         return BUFEMPTY;
  1851.  
  1852.     timeval = time (NULL) + TimeoutSecs;
  1853.  
  1854.     while ((int) PEEKBYTE () < 0)
  1855.     {
  1856.         if (!CARRIER)
  1857.             return NOCARRIER;
  1858.         if (time (NULL) > (time_t) timeval)
  1859.             return BUFEMPTY;
  1860.         time_release ();
  1861.     }
  1862.  
  1863.     return MODEM_IN ();
  1864. }
  1865.  
  1866. /*****************************************************************************/
  1867. /* Display start-of-transfer summary info                                    */
  1868. /*****************************************************************************/
  1869. void 
  1870. xfer_summary (char *xfertype, char *fname, long *len, short y)
  1871. {
  1872.     char buf[128];
  1873.  
  1874.     if (!un_attended || !fullscreen)
  1875.         gotoxy (2, y);
  1876.     else
  1877.         sb_move (filewin, y, 2);
  1878.  
  1879.     (void) sprintf (buf, "%s %12.12s;        0/%8ldb,%4ld min.                       ",
  1880.         xfertype, fname, *len, ((*len * 10L / cur_baud.rate_value * 100L / JANUS_EFFICIENCY + 59L) / 60L));
  1881.  
  1882.     if (!un_attended || !fullscreen)
  1883.     {
  1884.         (void) cputs (buf);
  1885.         (void) cputs (local_CEOL);
  1886.         update_y ();
  1887.     }
  1888.     else
  1889.     {
  1890.         sb_puts (filewin, buf);
  1891.         sb_show ();
  1892.     }
  1893. }
  1894.  
  1895. /*****************************************************************************/
  1896. /* Update any status line values which have changed                          */
  1897. /*****************************************************************************/
  1898. void
  1899. update_status (long *pos, long *oldpos, long left, int *oldeta, short y)
  1900. {
  1901.     char buf[16];
  1902.     register int eta;
  1903.  
  1904.     elapse_time ();
  1905.  
  1906.     if (*pos != *oldpos)
  1907.     {
  1908.         (void) sprintf (buf, "%8ld", *oldpos = *pos);
  1909.         if (!un_attended || !fullscreen)
  1910.         {
  1911.             gotoxy (POS_X, y);
  1912.             (void) cputs (buf);
  1913.         }
  1914.         else
  1915.         {
  1916.             sb_move (filewin, y, POS_X);
  1917.             sb_puts (filewin, buf);
  1918.         }
  1919.     }
  1920.  
  1921.     eta = (int) ((left * 10L / cur_baud.rate_value * 100L / JANUS_EFFICIENCY + 59L) / 60L);
  1922.     if (eta != *oldeta)
  1923.     {
  1924.         (void) sprintf (buf, "%4d Min", *oldeta = eta);
  1925.  
  1926.         if (!un_attended || !fullscreen)
  1927.         {
  1928.             gotoxy (ETA_X, y);
  1929.             (void) cputs (buf);
  1930.         }
  1931.         else
  1932.         {
  1933.             sb_move (filewin, y, ETA_X);
  1934.             sb_puts (filewin, buf);
  1935.         }
  1936.     }
  1937.  
  1938.     if (un_attended && fullscreen)
  1939.         sb_show ();
  1940. }
  1941.  
  1942. /*****************************************************************************/
  1943. /* Compute and print throughput                                              */
  1944. /*****************************************************************************/
  1945. long 
  1946. through (long *bytes, long *started)
  1947. {
  1948.     static char *scrn = "+CPS: %u (%lu bytes)  Efficiency: %lu%%%%";
  1949.     unsigned long elapsed;
  1950.     register word cps;
  1951.  
  1952.     elapsed = time (NULL) - *started;
  1953.     cps = (elapsed) ? (word) (*bytes / elapsed) : 0;
  1954.     j_status (scrn, cps, *bytes, cps * 1000L / cur_baud.rate_value);
  1955.     return elapsed;
  1956. }
  1957.  
  1958. /*****************************************************************************/
  1959. /* Get next file to request, if any                                          */
  1960. /*****************************************************************************/
  1961. static int LOCALFUNC 
  1962. get_filereq (byte req_started)
  1963. {
  1964.     char reqname[PATHLEN], linebuf[128], *holdname;
  1965.     register char *p;
  1966.     int gotone = FALSE;
  1967.     FILE *reqfile;
  1968.  
  1969. next_aka:
  1970.  
  1971.     if (!EMSI_flag)
  1972.     {
  1973.         holdname = HoldAreaNameMunge (&called_addr);
  1974.         (void) sprintf (reqname,
  1975.             "%s%s.REQ\0",
  1976.             holdname,
  1977.             Hex_Addr_Str (&called_addr));
  1978.     }
  1979.     else
  1980.     {
  1981.         holdname = HoldAreaNameMunge (&remote_akas[EMSI_raka]);
  1982.         (void) sprintf (reqname,
  1983.             "%s%s.REQ\0",
  1984.             holdname,
  1985.             Hex_Addr_Str (&remote_akas[EMSI_raka]));
  1986.     }
  1987.  
  1988.     if (req_started)
  1989.         mark_done (reqname);
  1990.  
  1991.     if (dexists (reqname))
  1992.     {
  1993.         if (!(remote_capabilities & WZ_FREQ))
  1994.             j_status (MSG_TXT (M_FREQ_DECLINED));
  1995.         else if (!(SharedCap & CANFREQ))
  1996.             j_status (MSG_TXT (M_REMOTE_CANT_FREQ));
  1997.         else
  1998.         {
  1999.             errno = 0;
  2000.             reqfile = fopen (reqname, read_ascii);
  2001.             if (reqfile != (FILE *) NULL)
  2002.                 errno = 0;
  2003.             if (!j_error (MSG_TXT (M_OPEN_MSG), reqname))
  2004.             {
  2005.                 while (!feof (reqfile))
  2006.                 {
  2007.                     linebuf[0] = '\0';
  2008.                     if (!fgets (p = linebuf, sizeof (linebuf), reqfile))
  2009.                         break;
  2010.                     while (*p >= ' ')
  2011.                         ++p;
  2012.                     *p = '\0';
  2013.                     if (linebuf[0] != ';')
  2014.                     {
  2015.                         (void) strcpy (Rxbuf, linebuf);
  2016.                         *(strchr (Rxbuf, '\0') + 1) = SharedCap;
  2017.                         gotone = TRUE;
  2018.                         break;
  2019.                     }
  2020.                 }
  2021.                 errno = 0;
  2022.                 (void) fclose (reqfile);
  2023.                 if (!gotone)
  2024.                 {
  2025.                     (void) unlink (reqname);
  2026.                 }
  2027.             }
  2028.         }
  2029.     }
  2030.  
  2031.     if (!gotone && EMSI_flag)
  2032.     {
  2033.         if (++EMSI_raka < num_rakas)
  2034.             goto next_aka;
  2035.     }
  2036.  
  2037.     return gotone;
  2038. }
  2039.  
  2040. /*****************************************************************************/
  2041. /* Record names of files to send in response to file request; callback       */
  2042. /* routine for respond_to_file_requests()                                    */
  2043. /*****************************************************************************/
  2044. static int 
  2045. record_reqfile (char *fname)
  2046. {
  2047.     FILE *pFileT;
  2048.  
  2049.     errno = 0;
  2050.     pFileT = fopen (ReqTmp, append_ascii);
  2051.     if (pFileT != (FILE *) NULL)
  2052.         errno = 0;
  2053.     if (!j_error (MSG_TXT (M_OPEN_MSG), ReqTmp))
  2054.     {
  2055.         errno = 0;
  2056.         (void) fputs (fname, pFileT);
  2057.         (void) j_error (MSG_TXT (M_WRITE_MSG), ReqTmp);
  2058.         (void) fputs ("\n", pFileT);
  2059.         (void) j_error (MSG_TXT (M_WRITE_MSG), ReqTmp);
  2060.         (void) fclose (pFileT);
  2061.         ++ReqRecorded;
  2062.         return TRUE;
  2063.     }
  2064.     return FALSE;
  2065. }
  2066.  
  2067. /*****************************************************************************/
  2068. /* Estimate transfer time for requested file(s); callback                    */
  2069. /* routine for respond_to_file_requests()                                    */
  2070. /*****************************************************************************/
  2071. static int 
  2072. timeof_reqfile (long filesize)
  2073. {
  2074.     int i;
  2075.  
  2076.     i = (int) (filesize * 10L / cur_baud.rate_value * 100L / JANUS_EFFICIENCY);
  2077.  
  2078.     /*
  2079.     * Since actual transfers don't occur while in file request code, we have to "reverse engineer" the testing for end-time.
  2080.     */
  2081.  
  2082.     if (CURRENT.time_Limit != 0)
  2083.     {
  2084.         if (((long) time (NULL) + i - freq_accum.time) > CURRENT.time_Limit)
  2085.             return i;
  2086.         freq_accum.time -= i;    /* Add time to (now-start) interval */
  2087.         return 0;
  2088.     }
  2089.     return i;
  2090. }
  2091.  
  2092. /*****************************************************************************/
  2093. /* Get next file which was requested, if any                                 */
  2094. /*****************************************************************************/
  2095. static byte LOCALFUNC 
  2096. get_reqname (byte first_req)
  2097. {
  2098.     register char *p;
  2099.     byte gotone = FALSE;
  2100.     FILE *pFileT;
  2101.     struct stat f;
  2102.  
  2103.     if (!first_req)
  2104.     {
  2105.         errno = 0;
  2106.         (void) close (Txfile);
  2107.         Txfile = -1;
  2108.         mark_done (ReqTmp);
  2109.     }
  2110.  
  2111.     if (dexists (ReqTmp))
  2112.     {
  2113.         errno = 0;
  2114.         pFileT = fopen (ReqTmp, read_ascii);
  2115.         if (pFileT != (FILE *) NULL)
  2116.             errno = 0;
  2117.         if (!j_error (MSG_TXT (M_OPEN_MSG), ReqTmp))
  2118.         {
  2119.             while (!feof (pFileT))
  2120.             {
  2121.                 Txfname[0] = '\0';
  2122.                 if (!fgets (p = Txfname, PATHLEN, pFileT))
  2123.                     break;
  2124.                 while (*p >= ' ')
  2125.                     ++p;
  2126.                 *p = '\0';
  2127.                 if (Txfname[0] != ';')
  2128.                 {
  2129.                     j_status (MSG_TXT (M_SENDING), Txfname);
  2130.                     errno = 0;
  2131.                     Txfile = share_open (Txfname, O_RDONLY | O_BINARY, DENY_WRITE);
  2132.                     if (Txfile != -1)
  2133.                         errno = 0;
  2134.                     if (j_error (MSG_TXT (M_OPEN_MSG), Txfname))
  2135.                         continue;
  2136.                     while (p >= Txfname && *p != '\\' && *p != ':')
  2137.                         --p;
  2138.                     (void) strcpy ((char *) Txbuf, ++p);
  2139.                     (void) stat (Txfname, &f);
  2140. #ifdef ANSI_TIME_T
  2141.                     f.st_mtime -= ANSI_TIME_T_DELTA;
  2142. #endif
  2143.                     (void) sprintf (strchr ((char *) Txbuf, '\0') + 1, "%lu %lo %o", Txlen = f.st_size, f.st_mtime, f.st_mode);
  2144.                     if (!un_attended || !fullscreen)
  2145.                         Tx_y = Next_y;
  2146.                     else
  2147.                         Tx_y = 1;
  2148.                     xfer_summary (MSG_TXT (M_SEND), p, &Txlen, Tx_y);
  2149.                     (void) time ((time_t *) & Txsttime);
  2150.                     gotone = TRUE;
  2151.                     break;
  2152.                 }
  2153.             }
  2154.             (void) fclose (pFileT);
  2155.             if (!gotone)
  2156.             {
  2157.                 (void) unlink (ReqTmp);
  2158.             }
  2159.         }
  2160.     }
  2161.  
  2162.     return gotone;
  2163. }
  2164.  
  2165. /*****************************************************************************/
  2166. /* Mark first unmarked line of file as done (comment it out)                 */
  2167. /*****************************************************************************/
  2168. static void LOCALFUNC 
  2169. mark_done (char *fname)
  2170. {
  2171.     char linebuf[128];
  2172.     FILE *fh;
  2173.     long pos;
  2174.  
  2175.     if (dexists (fname))
  2176.     {
  2177.         errno = 0;
  2178.         fh = fopen (fname, "rb+");
  2179.         if (fh != (FILE *) NULL)
  2180.             errno = 0;
  2181.         if (!j_error (MSG_TXT (M_OPEN_MSG), fname))
  2182.         {
  2183.             while (!feof (fh))
  2184.             {
  2185.                 pos = ftell (fh);
  2186.                 if (pos == -1L)
  2187.                     (void) j_error (MSG_TXT (M_SEEK_MSG), fname);
  2188.                 if (!fgets (linebuf, sizeof (linebuf), fh))
  2189.                     break;
  2190.                 if (linebuf[0] != ';')
  2191.                 {
  2192.                     if (fseek (fh, pos, SEEK_SET) == -1L)
  2193.                         (void) j_error (MSG_TXT (M_SEEK_MSG), fname);
  2194.                     (void) fputc (';', fh);
  2195.                     (void) j_error (MSG_TXT (M_WRITE_MSG), fname);
  2196.                     break;
  2197.                 }
  2198.             }
  2199.             (void) fclose (fh);
  2200.         }
  2201.     }
  2202. }
  2203.